
package com.feib.soeasy.job.importor;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;

import net.sourceforge.stripes.integration.spring.SpringBean;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import com.feib.soeasy.dao.PayerDao;
import com.feib.soeasy.dao.PayerTempDao;
import com.feib.soeasy.job.MailJob;
import com.feib.soeasy.job.service.ImportService;
import com.feib.soeasy.model.ColumnValidateError;
import com.feib.soeasy.model.MailQueue;
import com.feib.soeasy.model.UploadFile;
import com.feib.soeasy.service.PayerService;
import com.feib.soeasy.service.PayerTempService;


/**
 * @title (#)PyerImportJob.java<br>
 * @description <br>
 * @author Jimmy Liu<br>
 * @version 1.0.0 2010/11/25
 * @copyright Far Eastern International Bank Copyright (c) 2010<br>
 * @2011/3/16 create by Jimmy Liu<br>
 */
@Service("pyerImportJob")
@Scope(value=BeanDefinition.SCOPE_PROTOTYPE)
public class PyerImportJob implements Serializable{

    /**
     * serialVersionUID 與 Payer PayerTemp 同
     */
    private static final long serialVersionUID = 1L;
    
    
    public static Logger logger = LoggerFactory.getLogger(PyerImportJob.class);

    public static final SimpleDateFormat BASIC_DATE_TIME_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");

    @Resource(name="importService")
    private ImportService importService;

    @Resource(name="fileDownloadDestination")
    private String fileDownloadDestination;

    @Resource(name="itEmails")
    private String itEmails;

    @Resource(name="mailJob")
    private MailJob mailJob;

    @Resource(name="htmlMailFolder")
    private String htmlMailFolder;

    @Resource(name="defaultMailFrom")
    private String defaultMailFrom;

    @Resource(name="defaultMailReturnReceiptTo")
    private String defaultMailReturnReceiptTo;
    
    @Resource(name="txManager")
    private PlatformTransactionManager transactionManager;

    private UploadFile uploadFile = null;
    
    //新增 繳費人邏輯介面
    @Resource(name="payerService")
    private PayerService payerService;

    @Resource(name="payerTempService")
    private PayerTempService payerTempService;
    

    /**
     * 
     * @param uploadFilePk
     * @throws RuntimeException
     */
    public void execute(Long uploadFilePk)
    {
        Date start = new Date();
        boolean passed = true; // 預設檢核通過
        boolean isException = false; // 檢查過程中發生系統錯誤
        Exception exception = null;
        try {
            //有執行
            logger.info("繳款人資料整批匯入開始 -" + PyerImportJob.BASIC_DATE_TIME_FORMAT.format(start));

            // 取得待檢核檔案  
            uploadFile = loadUploadFile(uploadFilePk);

            if (null == uploadFile)
            {
                logger.info("資料表[SOEZ_UPLOAD_FILE]中無待檢核資料. 不作任何事情");
                return;
            }

            // 更新檔案為 檢查中
            try {
                this.uploadFile.setFileStatus(UploadFile.FILE_STATUS_IN_CHECKING);
                this.updateUploadFileStatus(this.uploadFile); 
            }
            catch (Exception e) {
                throw new RuntimeException("更新檔案狀態(檢查中)發生錯誤.", e);
            }

            logger.info("開始檢核檔案{}" ,  uploadFile.getFilePathOnServer());
            //fix 待改
            logger.info("payerTempService{}" ,  payerTempService);
            PayerTempFileChecker fileChecker = new PayerTempFileChecker(uploadFile, importService, payerTempService, fileDownloadDestination);
            passed = fileChecker.checkFile();

        }
        catch (Exception e) {
            passed = false;
            isException = true;
            exception = e;
            logger.error(e.getMessage(), e);
            logger.info("檢核檔案有問題");
        }
        finally
        {
            if (null == uploadFile)
            {
                return ;
            }

            try {

                if (isException || !passed)
                {
                    // 刪除 payerTemp 資料
                    logger.info("刪除 payerTemp 資料");
                    try {
                        //待改
                         payerTempService.deletePayerTempsByUploadFile(uploadFile);
                        //test1 使用 importService 新增method
                        //importService.deletePayerTempsByUploadFile(uploadFile);
                    }
                    catch (Exception e) {
                        throw new RuntimeException("刪除 payerTemp 資料發生錯誤.", e);
                    }

                    // 更新狀檔案態為 檢核未通過
                    logger.info("更新狀檔案態為 檢核未通過 ");
                    try {
                        this.uploadFile.setFileStatus(UploadFile.FILE_STATUS_CHECK_ERROR);
                        this.updateUploadFileStatus(this.uploadFile); 
                    }
                    catch (Exception e) {
                        throw new RuntimeException("更新檔案狀態(檢核未通過 )發生錯誤.", e);
                    }
                    
                    
                    try {
                        // 發送mail通知IT處理
                        if (isException)
                        {
                            logger.info("發送mail通知IT處理");
                            this.exceptionNotice(exception, this.uploadFile);
                        }
                        else
                        {
                            // 發送mail通知經辦重新處理
                            logger.info("發送mail通知經辦重新處理");
                            failNotice(this.uploadFile);
                        }
                    }
                    catch (Exception e) {
                        throw new RuntimeException("發送mail錯誤.", e);
                    }
                }

                if (passed)
                {
                    // 檢核通過
                    // 更新狀態為 待放行
                    try {
                        this.uploadFile.setFileStatus(UploadFile.FILE_STATUS_WAITING_CONFIRM);
                        this.updateUploadFileStatus(this.uploadFile); 
                    }
                    catch (Exception e) {
                        throw new RuntimeException("更新檔案狀態(待放行)發生錯誤.", e);
                    }

                    try {
                        // 發送mail通知經辦與主管放行
                        successNotice(this.uploadFile);
                    }
                    catch (Exception e) {
                        throw new RuntimeException("發送mail錯誤.", e);
                    }
                }
            }
            finally
            {
                Date end = new Date();
                logger.info("使用者整批匯入結束 -" + PyerImportJob.BASIC_DATE_TIME_FORMAT.format(end));
                logger.info("共費時  - " + ((end.getTime() - start.getTime()) / 1000) + " 秒 ");
            }
        }

    }




    /**
     * 取得待檢核資料
     * @param args
     * @return
     */
    protected UploadFile loadUploadFile(Long uploadFilePk)
    {
        if (null == uploadFilePk)
        {
            logger.info("沒有傳入參數，則取資料表[SOEZ_UPLOAD_FILE]中尚未檢核第1筆資料");
            return importService.getFirstUnCheckUploadFile();
        }
        else
        {
            return importService.getUnCheckUploadFileByPk(uploadFilePk);
        }
    }

    protected void updateUploadFileStatus(UploadFile uploadFile)
    {
        importService.updateUploadFileStatus(uploadFile);
    }

    public void exceptionNotice(Exception e, Long uploadFilePk) throws IOException
    {
        exceptionNotice(e, loadUploadFile(uploadFilePk));
    }
    /**
     * 系統錯誤通知
     * @param e
     * @param uploadFile
     * @throws IOException 
     */
    protected void exceptionNotice(Exception e, UploadFile uploadFile) throws IOException
    {
        // 沒有設定 IT EMALS
        if (StringUtils.isEmpty(itEmails))
        {
            if (null != uploadFile)
            {
                logger.warn("檔案 {} 檢核發生系統錯誤，但是因為沒有設定 IT Email，導致無法發送錯誤訊息給IT", uploadFile.getFileName());                
            }
            else
                logger.warn("檢核發生系統錯誤，但是因為沒有設定 IT Email，導致無法發送錯誤訊息給IT");
            logger.error("系統錯誤如下", e);
            return ;
        }
                
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        //待改
        List<ColumnValidateError> columnValidateErrors = importService.getColumnValidateErrors(uploadFile);
        
        if (null != e)
        {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            e.printStackTrace(pw);
            
            ColumnValidateError error = new ColumnValidateError();
            error.setExceptionMessage(sw.toString());
            columnValidateErrors.add(error);
        }        
        
        
        String messageTile = "[全方位企業收款服務] 繳款人資料上傳轉入失敗[" +uploadFile.getGroup().getGroupName()+"]";
        StringBuffer paragraph1 = new StringBuffer();
        paragraph1.append(uploadFile.getGroup().getGroupName()).append("於 ").append(dateFormat.format(uploadFile.getUpdatedDate()));
        paragraph1.append("上傳檔案 (").append(uploadFile.getFileName()).append("), 轉入時發生系統錯誤。");
        String[] paragraphs = new String[]{"您好", paragraph1.toString()};
        FileImportMailContent fileImportMailContent = new FileImportMailContent(messageTile, paragraphs, htmlMailFolder);
        
        fileImportMailContent.setColumnValidateErrors(columnValidateErrors);
        fileImportMailContent.setToBank(true);
        
        MailQueue mailQueue = fileImportMailContent.createMailQueue();
        mailQueue.setMailTo(itEmails);
        mailQueue.setMailFrom(defaultMailFrom);
        mailQueue.setMailReturnReceiptTo(defaultMailReturnReceiptTo);

        // 建立交易的定義，每一次都是新的 Transaction
        DefaultTransactionDefinition definition = new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
        TransactionStatus status = this.transactionManager.getTransaction(definition);
        try {
            importService.addMailQueue(mailQueue);
        }
        catch (Exception e2) {
            
            logger.error(e2.getMessage(),  e2);
            
            transactionManager.rollback(status);
            status = null; // roll back 不需要再呼叫 commit
        }
        if (null != status)
            transactionManager.commit(status);
        
        // 立即發送
        logger.debug("立即發送 Mail 給  {}", itEmails);
        mailJob.execute(mailQueue.getMailQueuePk());
        mailQueue = null; // free resource
    }

    /**
     * 檢核成功通知
     * 需發送給與上傳者同一個Group且擁有放行權限的人
     * @param uploadFile
     * @throws IOException 
     */
    protected void successNotice(UploadFile uploadFile) throws Exception
    {
        // 取得上傳者的 Group
        List<String> emails = importService.getConfirmUserEmail(uploadFile.getUploadUser().getGroup());
        if (null != emails && 0 != emails.size())
        {
            StringBuffer mailTo = new StringBuffer();
            for(String email : emails)
                mailTo.append(email).append(",");
            
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
            
            String messageTile = "[全方位企業收款服務] 繳款人資料上傳回覆 [" +uploadFile.getFileName()+"]";
            StringBuffer paragraph1 = new StringBuffer();
            paragraph1.append("您於 ").append(dateFormat.format(uploadFile.getUpdatedDate()));
            paragraph1.append(" 所上傳檔案，").append(uploadFile.getFileName()).append("， 已成功轉入。");
            paragraph1.append("<br/>請您至系統確認資料內容。");
            String[] paragraphs = new String[]{"您好", paragraph1.toString(), "謝謝"};
            
            FileImportMailContent fileImportMailContent = new FileImportMailContent(messageTile, paragraphs, htmlMailFolder);
            
            MailQueue mailQueue = fileImportMailContent.createMailQueue();
            mailQueue.setMailTo(mailTo.toString());
            mailQueue.setMailFrom(defaultMailFrom);
            mailQueue.setMailReturnReceiptTo(defaultMailReturnReceiptTo);

            // 建立交易的定義，每一次都是新的 Transaction
            DefaultTransactionDefinition definition = new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
            TransactionStatus status = this.transactionManager.getTransaction(definition);
            try {
                importService.addMailQueue(mailQueue);
            }
            catch (Exception e2) {              
                transactionManager.rollback(status);
                status = null; // roll back 不需要再呼叫 commit
                throw e2;
            }
            if (null != status)
                transactionManager.commit(status);
            
            // 立即發送
            logger.debug("立即發送 Mail 給  {}", itEmails);
            mailJob.execute(mailQueue.getMailQueuePk());
            mailQueue = null; // free resource
        }
    }

    /**
     * 檢核失敗通知
     * @param uploadFile
     * @throws IOException 
     */
    protected void failNotice(UploadFile uploadFile) throws Exception
    {
        String mailTo = uploadFile.getUploadUser().getUserEmail();
        
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");

        if (null != mailTo && 0!= mailTo.length())
        {
            List<ColumnValidateError> columnValidateErrors = importService.getColumnValidateErrors(uploadFile);
            
            String messageTile = "[全方位企業收款服務] 繳款人資料上傳回覆 [" +uploadFile.getFileName()+"]";
            StringBuffer paragraph1 = new StringBuffer();
            paragraph1.append("您於 ").append(dateFormat.format(uploadFile.getUpdatedDate()));
            paragraph1.append(" 所上傳檔案，").append(uploadFile.getFileName()).append("， 因故轉入失敗。");
            paragraph1.append("<br/>請先錯誤修正後，再重新上傳。");
            String[] paragraphs = new String[]{"您好", paragraph1.toString(), "謝謝"};
            FileImportMailContent fileImportMailContent = new FileImportMailContent(messageTile, paragraphs, htmlMailFolder);
            
            fileImportMailContent.setColumnValidateErrors(columnValidateErrors);
            
            MailQueue mailQueue = fileImportMailContent.createMailQueue();
            mailQueue.setMailTo(mailTo);
            mailQueue.setMailFrom(defaultMailFrom);
            mailQueue.setMailReturnReceiptTo(defaultMailReturnReceiptTo);

            // 建立交易的定義，每一次都是新的 Transaction
            DefaultTransactionDefinition definition = new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
            TransactionStatus status = this.transactionManager.getTransaction(definition);
            try {
                importService.addMailQueue(mailQueue);
            }
            catch (Exception e2) {                
                transactionManager.rollback(status);
                status = null; // roll back 不需要再呼叫 commit
                throw e2;
            }
            if (null != status)
                transactionManager.commit(status);
            
            // 立即發送
            logger.debug("立即發送 Mail 給  {}", itEmails);
            mailJob.execute(mailQueue.getMailQueuePk());
            mailQueue = null; // free resource
        }

    }

    
    
    
    
    
}
